/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package simulator.engine;

import db.MysqlAdapter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author 490060
 */
public class Inventory 
{   
    //Constants for deciding familyType 
    public static final short FAMILY_WITH_TWO_INFANTS = 1;
    public static final short COUPLE_WITH_ONE_DOG = 2;
    public static final short THE_LEGENDARY_SINGLE_GUY = 3;
    public static final short LONLEY_PARENT_WITH_ONE_CHILD = 4;
    public static final short OLD_COUPLE = 5;
    public static final short KINDERGARTEN = 6;
 
    private int currentFamily = 0;
 
    //Constants for deciding category
    public static final short BATHROOM_EQUIPMENT = 0;
    public static final short ENTERTAINMENT = 1;
    public static final short HEATED_WATER = 2;
    public static final short KITCHEN_EQUIPMENT = 3;
    public static final short WASHING_MACHINE = 4;
           
    //Constant array for deciding inventory category
    private static final String[] category = 
    {
        "'Bathroom_equipment'",	
        "'Entertainment'", 
        "'Heated_water'", 
        "'Kitchen_equipment'", 
        "'Wahsing_machine'"
    };
    
    //Array with energy-usage per hour running at max capacity.
    private float[] maxEnergyUsage = new float[category.length];
    
    //Variables
    private MysqlAdapter db = new MysqlAdapter();
    private Structure structure;
    
    //Random generator
    private Random rand = new Random();

    
    /**
     * Constructs an empty Inventory Energy-usage simulator
     */
    public Inventory()
    {
        
    }
    
    /**
     * Constructs a Inventory Energy-usage simulator
     * with parameters FamilyType and ProfileID
     */
    public Inventory(int familyType, int profileID)
    {
        currentFamily = familyType;
        try
        {
//            setHouseProfileFromDatabase(profileID);
            structure = new Structure(profileID);
            System.out.println("House profile selected from database");
        }
        catch(Exception e)
        {
            setExampleHouseProfile((short)profileID);
            System.out.println("House profile selected from code");
        }
    }
    
    public void setFamilyType(short familyType)
    {
        currentFamily = familyType;
    }
    
   /**
     * Numbers represent kW
     * @param s 
     */
    private void setExampleHouseProfile(short s)
    {
        float[] output = new float[category.length];
        System.out.println("House profile selected from code");
        switch(s){    
            case 0:
                output[BATHROOM_EQUIPMENT] = 50.0f;
                output[ENTERTAINMENT] = 20.0f;
                output[HEATED_WATER] = 120.0f;
                output[KITCHEN_EQUIPMENT] = 10.0f;
                output[WASHING_MACHINE] = 50.0f;
                break;
                
            case 1:
                output[BATHROOM_EQUIPMENT] = 10.0f;
                output[ENTERTAINMENT] = 10.0f;
                output[HEATED_WATER] = 100.0f;
                output[KITCHEN_EQUIPMENT] = 10.0f;
                output[WASHING_MACHINE] = 0.0f;
                break;
                
            case 2:
                output[BATHROOM_EQUIPMENT] = 10.0f;
                output[ENTERTAINMENT] = 120.0f;
                output[HEATED_WATER] = 80.0f;
                output[KITCHEN_EQUIPMENT] = 30.0f;
                output[WASHING_MACHINE] = 500.0f;
                break;
                
            default:
                output[BATHROOM_EQUIPMENT] = 60.0f;
                output[ENTERTAINMENT] = 50.0f;
                output[HEATED_WATER] = 100.0f;
                output[KITCHEN_EQUIPMENT] = 20.0f;
                output[WASHING_MACHINE] = 100.0f;
                break;
        }
        maxEnergyUsage = output;    
    }
    
    
    /**
     * Returns a float that represents the total amount of energy used in one category at a specific time of day
     * @param _category Constant that represents the category
     * @param hour short that represents witch time of day it is
     * @param onHoliday if the family is on vacation this time of day, insert true
     * @return 
     */
    public float getSimulatedHour(short _category, short hour, boolean onHoliday) throws InterruptedException
    {      
        ArrayList<float[]> userPattern = null;
        ArrayList<float[]> realisticUserPattern = new ArrayList<float[]>();
        
        try {
            if(onHoliday)
            {
                userPattern = getInventoryUseageFromDB(currentFamily, true);

            }
            else
            {
                userPattern = getInventoryUseageFromDB(currentFamily, false);
                System.out.print("USERPATTERN:");
                for(int i = 0; i < userPattern.size(); i++)
                    System.out.print(userPattern.get(i)[4] + "");
                System.out.println("");
            }
            
        } catch (SQLException ex) {
            Logger.getLogger(Inventory.class.getName()).log(Level.SEVERE, null, ex);
        }
        for(float[] f: userPattern)
            realisticUserPattern.add(generateRealisticUserPattern(f, getExampleDiversityController()));
        
        float  actualEnergyUsage = 0;
        
        if(userPattern.get(_category).length > hour)
        {
            actualEnergyUsage = structure.getMaxEnergyUsage(getStringAssignedToCategory(_category));
            actualEnergyUsage *= userPattern.get(_category)[hour] / 100;
        }
        
    
        return actualEnergyUsage;
    }
    
    
    /**
     * Returns a float that represents the total amount of energy used in one day
     * @param hour Can be between 0 - 24. Represents the time of day
     * @param onHoliday Is the family on vacation this particular hour?
     * @return 
     */
    public float getSimulatedHour(short hour, boolean onHoliday) throws InterruptedException
    {
        float actualEnergyUsage = 0;
        
        for(short i = 0; i < category.length; i++)
        {
            actualEnergyUsage += getSimulatedHour(i, hour, onHoliday);
        }
        return actualEnergyUsage;
    }
    
    /**
     * Uses the getSimulatedHour method to compute the energy usage for one day
     * @param onHoliday is the family on vacation this day?
     * @return 
     */
    public float getSimulatedDay(boolean onHoliday) throws InterruptedException
    {
        float actualEnergyUsage = 0;
        for(short i = 0; i <= 24; i++)
        {
            actualEnergyUsage += getSimulatedHour(i , onHoliday);
        }
        return actualEnergyUsage;
    }
    
    private String getStringAssignedToCategory(short cat)
    {
//    public static final short BATHROOM_EQUIPMENT = 0;
//    public static final short ENTERTAINMENT = 1;
//    public static final short HEATED_WATER = 2;
//    public static final short KITCHEN_EQUIPMENT = 3;
//    public static final short WASHING_MACHINE = 4;
        String out;
        
        switch(cat)
        {
            case(0):
                out =  "Bathroom_equipment";
                break;
            case(1):
                out = "Entertainment";
                break;
            case(2):
                out = "Heated_water";
                break;
            case(3):
                out = "Kitchen_equipment";
                break;
            default:
                out = "Wahsing_machine";
                break;
        }
        return out;
    }
    
    /**
     * Returns returns a constant that represents the category  
     * @param cat Category name
     * @return Constant that represents the category
     */
    public static int getConstantAssignedToCategory(String cat)
    {

        if(cat.equals("Bathroom_equipment"))
        {
            return BATHROOM_EQUIPMENT;
        }
        
        else if(cat.equals("Entertainment"))
        {
            return ENTERTAINMENT;
        }
        
        else if(cat.equals("Heated_water"))
        {
            return HEATED_WATER;
        }
        
        else if(cat.equals("Kitchen_equipment"))
        {
            return KITCHEN_EQUIPMENT;
        }
        
        else if(cat.equals("Wahsing_machine"))
        {
            return WASHING_MACHINE;
        }
        else 
        {
            System.out.println("Failed to assign a number");
             return -1;
        }
    }
    
    /**
     *  Returns an Arraylist with one float[24] for each available category. 
     *  each float tells us how many percent of one category is being used
     *  this hour. getInventoryUseageFromDB.get(ENTERTAINMENT)[2] == 65.7. 
     *  At 02:00, 65.7% of the entertainment category is being used.
     */
    private ArrayList<float[]> getInventoryUseageFromDB(int familyType, 
            boolean onHoliday) throws SQLException, InterruptedException
    {
        ArrayList<float[]> output = new ArrayList<float[]>();
        
        for(int i = 0; i < category.length; i++)
        {
            output.add(db.getInventoryUseage(familyType, category[i], 
                    onHoliday));
            //Thread.sleep(2000);
        }
//        for(int i = 0; i < output.size(); i++)
//            for(int j = 0; j < output.get(j).length; j++)
//                System.out.println(output.get(i)[j]);
       
        return output;
    }
    
    /**
     * 
     * @param usageArrayList that represents how likely a family-profile is to 
     * do a certain action at the exact time specified in the usage 
     * pattern. Space one represents the exact time, space two represents
     * one hour after/before the exact time and so on.
     * for example. list [90, 5, 5] 90 family-profiles will do the action
     * at the specified time, 5 family-profiles will do the action one hour
     * before or after and 5 family profiles will do the action two hours 
     * before or after
     * 
     * @return array with a more realistic usage pattern
     */
    private float[] generateRealisticUserPattern(float[] usagePattern, 
            ArrayList<Float> diversityController)
    {
        int propability = rand.nextInt(100);
        int limit = 0;
        float[] usage = usagePattern;
        
        for(int i = 0; i < usage.length; i++)
        {
            for(int j = 0; j < diversityController.size(); j++)
            {
                limit += diversityController.get(j);
                if(propability <= limit)
                    usage = moveSpaces(usage, j, i);
            }
        }
        
        return usage;
    }
    
//    private ArrayList<Float> arrayToList(float[] intArray)
//    {
//        ArrayList<Float> out = new ArrayList();
//        for(float element : intArray)
//            out.add(element);
//        return out;
//    }
//    
//    private float[] listToArray(ArrayList<Float> list)
//    {
//        float[] out = new float[list.size()];
//        for(int i = 0; i < out.length; i++)
//            out[i] = list.get(i);
//        return out;
//    }
    
    /**
     * Moves an element in parameter array in a random direction
     * @param usagePattern
     * @param spaces how many spaces to move
     * @param index element in array to be moved
     * @return 
     */
    private float[] moveSpaces(float[] usagePattern, int spaces, int index)
    {
        float tempValue;
        int toBeSwitched;
        boolean sendForward = rand.nextBoolean();
        
        if(sendForward)
            toBeSwitched = index + spaces;
        else 
            toBeSwitched = index - spaces;
        
        if(toBeSwitched < 0)
            toBeSwitched = usagePattern.length - toBeSwitched - 1;
        if(toBeSwitched >= usagePattern.length)
            toBeSwitched = toBeSwitched - usagePattern.length;
        
        
        tempValue = usagePattern[toBeSwitched];
        usagePattern[toBeSwitched] = usagePattern[index];
        usagePattern[index] = tempValue;
        
        return usagePattern;
    }
    
    /**
     * 
     * @return  
     */
    private ArrayList<Float> getExampleDiversityController()
    {
        ArrayList<Float> output = new ArrayList();
        output.add(95.0f);
        output.add(5.0f);
        
        return output;
    }
   
    public static void main(String[] args) throws SQLException, InterruptedException
    {      
        Inventory inv = new Inventory(THE_LEGENDARY_SINGLE_GUY, 2);
        
        //System.out.println(inv.getSimulatedHour((short) 4, true));
        System.out.println(inv.getSimulatedDay(false));

        
    }
}


